// 测试生产者消费者模型 -- 环形队列

//本测试演示了 : 中间交易场所中存不同的数据
// 1. 存放数字
// 2. 存放自定义类
// 3. 存放函数指针
// 4. ..... 等等都可以存饭 , 因为实现是基于模版的 !!!!
// 所以 , 测试模版的可用用 !!

// 生产者和消费者(线程扮演) , 中间交易场所

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include "CircularQueue.hpp"
#include "Task.hpp"

// 展开环形队列的命名空间 , 方便后续使用
using namespace CircularQueueModel;

// int data = 1;
void *productor(void *args)
{
    // 生产者生产 , 往中间交易场所中生产数据
    // 获取传过来的中间交易场所 , 环形队列
    // 里面放任务类型
    // CQueue<Task> *cq = static_cast<CQueue<Task> *>(args);
    // 里面放数字
    // CQueue<int> *cq = static_cast<CQueue<int> *>(args);
    // 里面放任务函数指针
    CQueue<task_t> *cq = static_cast<CQueue<task_t> *>(args);
    while (true)
    {
        // 数据是一个整数时 :
         sleep(1);
        //   生产数据
        //  cq->Equeue(data++);
        //  std::cout << "我生产了一个数据 [ " << data << " ] " << std::endl;

        // 数据是任务时 :
        // int x = 1, y = 1;
        // Task t(x++, y++); // 定义一个任务类型
        // cq->Equeue(t);    // 生产一个任务
        // std::cout << " 我生产了一个任务 ! " << std::endl;

        //生产任务就是把任务函数放到中间交易场所
        cq->Equeue(DownLoad);
        std::cout << " 我生产了一个任务 ! " << std::endl;

    }
}

void *consumer(void *args)
{
    // 消费者消费 , 从中间交易场所中拿数据消费
    // 获取传过来的中间交易场所 , 环形队列
    // 里面放任务类型
    // CQueue<Task> *cq = static_cast<CQueue<Task> *>(args);
    // 里面放数字
    // CQueue<int> *cq = static_cast<CQueue<int> *>(args);
    // 里面放任务函数指针
    CQueue<task_t> *cq = static_cast<CQueue<task_t> *>(args);
    while (true)
    {
        // 数据是一个整数时 :
        //sleep(1);

        // int data = cq->Pop();
        // std::cout << "我拿到了一个数据 , 数据为 : " << data << " , 我要消费它" << std::endl;

        // 数据是任务时 :
        // Task t = cq->Pop(); // 得到一个任务
        // t.Execute();        // 执行任务
        // std::cout << "我执行了任务 , " << t.X() << "+" << t.Y() << " = " << t.Result() << std::endl;
    
        task_t t = cq->Pop();
        t(); // 函数回调 , 可以找到 Task 类中的 task_t 类型的函数
    }
}

int main()
{
    // 1. 申请中间场所 , 申请环形队列
    // CQueue<int> *cq = new CQueue<int>(); // 走构造

    // 里面是任务
    // CQueue<Task> *cq = new CQueue<Task>(); // 走构造
    // 里面是任务
    CQueue<task_t> *cq = new CQueue<task_t>(); // 走构造

    // 2. 创建生产者和消费者 , 2个生产者和3个消费者 , 创建5个线程
    // 2.1 创建类型
    pthread_t p[2], c[3];
    // 2.2 创建时把中间交易产所传过去
    pthread_create(p, nullptr, productor, cq);
    pthread_create(p + 1, nullptr, productor, cq);

    pthread_create(c, nullptr, consumer, cq);
    pthread_create(c + 1, nullptr, consumer, cq);
    pthread_create(c + 2, nullptr, consumer, cq);

    // 等待线程 , 等待哪个线程
    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);
    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(c[2], nullptr);

    return 0;
}